use serde::{ser::SerializeTuple, Serialize, Serializer};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Date {
    Year(u16),
    Month(Month),
    Week(Week),
    Day(Day),
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Day {
    pub year: u16,
    pub month: u8,
    pub day: u8,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Month {
    pub year: u16,
    pub month: u8,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Week {
    pub year: u16,
    pub week: u8,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Year(pub u16);

impl Month {
    pub fn get_id(&self) -> u32 {
        self.year as u32 * 12 + self.month as u32
    }
}

impl Week {
    pub fn get_id(&self) -> u32 {
        self.year as u32 * 53 + self.week as u32
    }
}

impl Day {
    pub fn get_id(&self) -> u32 {
        (self.year as u32 * 12 + self.month as u32) * 31 + self.day as u32
    }
}

impl Serialize for Year {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut tup = serializer.serialize_tuple(3)?;
        tup.serialize_element(&self.0)?;
        tup.end()
    }
}

impl Serialize for Month {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut tup = serializer.serialize_tuple(3)?;
        tup.serialize_element(&self.year)?;
        tup.serialize_element(&self.month)?;
        tup.end()
    }
}

impl Serialize for Week {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut tup = serializer.serialize_tuple(3)?;
        tup.serialize_element(&self.year)?;
        tup.serialize_element(&self.week)?;
        tup.end()
    }
}

impl Serialize for Day {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut tup = serializer.serialize_tuple(3)?;
        tup.serialize_element(&self.year)?;
        tup.serialize_element(&self.month)?;
        tup.serialize_element(&self.day)?;
        tup.end()
    }
}
